package net.opentsdb.utils;

import cn.hutool.core.util.StrUtil;
import org.jboss.netty.util.internal.StringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.FileInputStream;
import java.io.IOException;
import java.util.*;

/**
 * @author Hujf
 * @title: Config
 * @date 2021-09-08 15:57
 * @description: opentsdb的配置类
 */
public class Config {

    private static final Logger LOG = LoggerFactory.getLogger(Config.class);

    public static final boolean IS_WINDOWS = System.getProperty("os.name", "").contains("Windows");
    private boolean enable_compaction = true;

    public boolean isAuto_metric() {
        return auto_metric;
    }

    public void setAuto_metric(boolean auto_metric) {
        this.auto_metric = auto_metric;
    }

    private boolean auto_metric = false;

    private boolean auto_tagk = true;

    private boolean auto_tagv = true;

    private boolean enable_compactions = true;

    private boolean enable_appends = false;

    private boolean repair_appends = false;

    private boolean enable_realtime_ts = false;

    /** tsd.core.meta.enable_realtime_uid */
    private boolean enable_realtime_uid = false;

    /** tsd.core.meta.enable_tsuid_incrementing */
    private boolean enable_tsuid_incrementing = false;

    /** tsd.core.meta.enable_tsuid_tracking */
    private boolean enable_tsuid_tracking = false;

    /** tsd.http.request.enable_chunked */
    private boolean enable_chunked_requests = false;

    /** tsd.storage.fix_duplicates */
    private boolean fix_duplicates = false;

    /** tsd.http.header_tag */
    private String http_header_tag = null;

    /** tsd.http.request.max_chunk */
    private int max_chunked_requests = 4096;

    /** tsd.core.tree.enable_processing */
    private boolean enable_tree_processing = false;

    /** tsd.storage.hbase.scanner.maxNumRows */
    private int scanner_max_num_rows = 128;

    /** tsd.storage.use_otsdb_timestamp */
    /** Sets the HBase cell timestamp equal to metric timestamp */
    private boolean use_otsdb_timestamp = true;

    private long get_date_tiered_compaction_start = 0;

    /** tsd.storage.use_max_value */
    /** Used for resolving between data coming in at same timestamp */
    /** If set to true, the maximum value will be returned, minimum */
    private boolean use_max_value = true;

    protected String config_location;

    protected static final HashMap<String, String> default_map =
            new HashMap<String, String>();

    protected final HashMap<String, String> properties =
            new HashMap<String, String>();

    public Config(String config_file) {
    }

    public Config(final boolean auto_load_config) {
        if (auto_load_config) {
            loadConfig();
        }
        setDefaults();
    }

    private void loadConfig() {
        //如果有指定配置文件
        if (config_location != null && !config_location.isEmpty()) {
            loadConfig(config_location);
            return;
        }

        final ArrayList<String> file_locations = new ArrayList<String>();
        file_locations.add("opentsdb.conf");
        String path = this.getClass().getResource("/").getPath();
        file_locations.add(path + "\\opentsdb.conf");

        for (String file : file_locations) {
            try {
                FileInputStream fileInputStream = new FileInputStream(file);
                Properties prop = new Properties();
                prop.load(fileInputStream);

                loadHashMap(prop);

            } catch (Exception e) {
                LOG.info("file is not found or load" + path);
                continue;
            }
            LOG.info("Successfully loaded configuration file  " + path);
            config_location = file;
            return;
        }
        LOG.info("No configuration found, will use defaults");
    }

    private void loadConfig(String file) {
        FileInputStream fileInputStream = null;
        try {
            fileInputStream = new FileInputStream(file);
            Properties properties = new Properties();
            properties.load(fileInputStream);

            loadHashMap(properties);
            LOG.info("Successfully loaded configuration file: " + file);

            config_location = file;
        } catch (Exception e) {
            throw new RuntimeException("加载配置文件出错，" + file);
        } finally {
            try {
                fileInputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private void loadHashMap(final Properties props) {
        properties.clear();
        Enumeration e = props.propertyNames();
        while (e.hasMoreElements()) {
            String key = (String) e.nextElement();
            properties.put(key, props.getProperty(key));
        }
    }

    public String getString(String property) {
        return properties.get(property);
    }

    protected void setDefaults() {
        // map.put("tsd.network.port", ""); // does not have a default, required
        // map.put("tsd.http.cachedir", ""); // does not have a default, required
        // map.put("tsd.http.staticroot", ""); // does not have a default, required
        default_map.put("tsd.mode", "rw");
        default_map.put("tsd.no_diediedie", "false");
        default_map.put("tsd.network.bind", "0.0.0.0");
        default_map.put("tsd.network.worker_threads", "");
        default_map.put("tsd.network.async_io", "true");
        default_map.put("tsd.network.tcp_no_delay", "true");
        default_map.put("tsd.network.keep_alive", "true");
        default_map.put("tsd.network.reuse_address", "true");
        default_map.put("tsd.core.authentication.enable", "false");
        default_map.put("tsd.core.authentication.plugin", "");
        default_map.put("tsd.core.auto_create_metrics", "false");
        default_map.put("tsd.core.auto_create_tagks", "true");
        default_map.put("tsd.core.auto_create_tagvs", "true");
        default_map.put("tsd.core.connections.limit", "0");
        default_map.put("tsd.core.enable_api", "true");
        default_map.put("tsd.core.enable_ui", "true");
        default_map.put("tsd.core.meta.enable_realtime_ts", "false");
        default_map.put("tsd.core.meta.enable_realtime_uid", "false");
        default_map.put("tsd.core.meta.enable_tsuid_incrementing", "false");
        default_map.put("tsd.core.meta.enable_tsuid_tracking", "false");
        default_map.put("tsd.core.meta.cache.enable", "false");
        default_map.put("tsd.core.plugin_path", "");
        default_map.put("tsd.core.socket.timeout", "0");
        default_map.put("tsd.core.tree.enable_processing", "false");
        default_map.put("tsd.core.preload_uid_cache", "false");
        default_map.put("tsd.core.preload_uid_cache.max_entries", "300000");
        default_map.put("tsd.core.storage_exception_handler.enable", "false");
        default_map.put("tsd.core.uid.random_metrics", "false");
        default_map.put("tsd.core.bulk.allow_out_of_order_timestamps", "false");
        default_map.put("tsd.query.filter.expansion_limit", "4096");
        default_map.put("tsd.query.skip_unresolved_tagvs", "false");
        default_map.put("tsd.query.allow_simultaneous_duplicates", "true");
        default_map.put("tsd.query.enable_fuzzy_filter", "true");
        default_map.put("tsd.query.limits.bytes.default", "0");
        default_map.put("tsd.query.limits.bytes.allow_override", "false");
        default_map.put("tsd.query.limits.data_points.default", "0");
        default_map.put("tsd.query.limits.data_points.allow_override", "false");
        default_map.put("tsd.query.limits.overrides.interval", "60000");
        default_map.put("tsd.query.multi_get.enable", "false");
        default_map.put("tsd.query.multi_get.limit", "131072");
        default_map.put("tsd.query.multi_get.batch_size", "1024");
        default_map.put("tsd.query.multi_get.concurrent", "20");
        default_map.put("tsd.query.multi_get.get_all_salts", "false");
        default_map.put("tsd.rpc.telnet.return_errors", "true");
        // Rollup related settings
        default_map.put("tsd.rollups.enable", "false");
        default_map.put("tsd.rollups.tag_raw", "false");
        default_map.put("tsd.rollups.agg_tag_key", "_aggregate");
        default_map.put("tsd.rollups.raw_agg_tag_value", "RAW");
        default_map.put("tsd.rollups.block_derived", "true");
        default_map.put("tsd.rtpublisher.enable", "false");
        default_map.put("tsd.rtpublisher.plugin", "");
        default_map.put("tsd.search.enable", "false");
        default_map.put("tsd.search.plugin", "");
        default_map.put("tsd.stats.canonical", "false");
        default_map.put("tsd.startup.enable", "false");
        default_map.put("tsd.startup.plugin", "");
        default_map.put("tsd.storage.hbase.scanner.maxNumRows", "128");
        default_map.put("tsd.storage.fix_duplicates", "false");
        default_map.put("tsd.storage.flush_interval", "1000");
        default_map.put("tsd.storage.hbase.data_table", "tsdb");
        default_map.put("tsd.storage.hbase.uid_table", "tsdb-uid");
        default_map.put("tsd.storage.hbase.tree_table", "tsdb-tree");
        default_map.put("tsd.storage.hbase.meta_table", "tsdb-meta");
        default_map.put("tsd.storage.hbase.zk_quorum", "localhost");
        default_map.put("tsd.storage.hbase.zk_basedir", "/hbase");
        default_map.put("tsd.storage.hbase.prefetch_meta", "false");
        default_map.put("tsd.storage.enable_appends", "false");
        default_map.put("tsd.storage.repair_appends", "false");
        default_map.put("tsd.storage.enable_compaction", "true");
        default_map.put("tsd.storage.compaction.flush_interval", "10");
        default_map.put("tsd.storage.compaction.min_flush_threshold", "100");
        default_map.put("tsd.storage.compaction.max_concurrent_flushes", "10000");
        default_map.put("tsd.storage.compaction.flush_speed", "2");
        default_map.put("tsd.timeseriesfilter.enable", "false");
        default_map.put("tsd.uid.use_mode", "false");
        default_map.put("tsd.uid.lru.enable", "false");
        default_map.put("tsd.uid.lru.name.size", "5000000");
        default_map.put("tsd.uid.lru.id.size", "5000000");
        default_map.put("tsd.uidfilter.enable", "false");
        default_map.put("tsd.core.stats_with_port", "false");
        default_map.put("tsd.http.show_stack_trace", "true");
        default_map.put("tsd.http.query.allow_delete", "false");
        default_map.put("tsd.http.header_tag", "");
        default_map.put("tsd.http.request.enable_chunked", "false");
        default_map.put("tsd.http.request.max_chunk", "4096");
        default_map.put("tsd.http.request.cors_domains", "");
        default_map.put("tsd.http.request.cors_headers", "Authorization, "
                + "Content-Type, Accept, Origin, User-Agent, DNT, Cache-Control, "
                + "X-Mx-ReqToken, Keep-Alive, X-Requested-With, If-Modified-Since");
        default_map.put("tsd.query.timeout", "0");
        default_map.put("tsd.storage.use_otsdb_timestamp", "false");
        default_map.put("tsd.storage.use_max_value", "true");
        default_map.put("tsd.storage.get_date_tiered_compaction_start", "0");

        for (Map.Entry<String, String> entry : default_map.entrySet()) {
            if (!properties.containsKey(entry.getKey()))
                properties.put(entry.getKey(), entry.getValue());
        }

        loadStaticVariables();
    }

    private void loadStaticVariables() {
        auto_metric = this.getBoolean("tsd.core.auto_create_metrics");
        auto_tagk = this.getBoolean("tsd.core.auto_create_tagks");
        auto_tagv = this.getBoolean("tsd.core.auto_create_tagvs");
        enable_compactions = this.getBoolean("tsd.storage.enable_compaction");
        enable_appends = this.getBoolean("tsd.storage.enable_appends");
        repair_appends = this.getBoolean("tsd.storage.repair_appends");
        enable_chunked_requests = this.getBoolean("tsd.http.request.enable_chunked");
        enable_realtime_ts = this.getBoolean("tsd.core.meta.enable_realtime_ts");
        enable_realtime_uid = this.getBoolean("tsd.core.meta.enable_realtime_uid");
        enable_tsuid_incrementing =
                this.getBoolean("tsd.core.meta.enable_tsuid_incrementing");
        enable_tsuid_tracking =
                this.getBoolean("tsd.core.meta.enable_tsuid_tracking");
        if (this.hasProperty("tsd.http.request.max_chunk")) {
            max_chunked_requests = this.getInt("tsd.http.request.max_chunk");
        }
        if (this.hasProperty("tsd.http.header_tag")) {
            http_header_tag = this.getString("tsd.http.header_tag");
        }
        enable_tree_processing = this.getBoolean("tsd.core.tree.enable_processing");
        fix_duplicates = this.getBoolean("tsd.storage.fix_duplicates");
        scanner_max_num_rows = this.getInt("tsd.storage.hbase.scanner.maxNumRows");
        use_otsdb_timestamp = this.getBoolean("tsd.storage.use_otsdb_timestamp");
        get_date_tiered_compaction_start = this.getLong("tsd.storage.get_date_tiered_compaction_start");
        use_max_value = this.getBoolean("tsd.storage.use_max_value");

    }

    public final long getLong(final String property) {
        return Long.parseLong(TsdStrUtil.sanitize(properties.get(property)));
    }

    public boolean hasProperty(String prop) {
        String val = properties.get(prop);
        if (TsdStrUtil.isNullOrEmpty(val)) {
            return false;
        }
        return true;
    }

    public int getInt(String property) {
        return Integer.parseInt(TsdStrUtil.sanitize(properties.get(property)));
    }

    public boolean getBoolean(String property) {
        final String val = properties.get(property).trim().toUpperCase();
        switch (val){
            case "1":
            case "TRUE":
            case "YES" :
                return true;
            default: return false;
        }
    }

    public String configLocation() {
        return config_location;
    }

    public boolean enable_tree_processing() {
        return enable_tree_processing;
    }

    public boolean enable_realtime_uid() {
        return enable_realtime_uid;
    }

    public boolean enable_tsuid_incrementing() {
        return enable_tsuid_incrementing;
    }

    public boolean enable_realtime_ts() {
        return enable_realtime_ts;
    }

    public void setAutoMetric(boolean autoMetric) {
        this.auto_metric = auto_metric;
        properties.put("tsd.core.auto_create_metrics",
                Boolean.toString(auto_metric));
    }

    public void overrideConfig(String s, String aTrue) {
    }

    public boolean enable_chunked_requests() {
        return enable_chunked_requests;
    }

    //最大值
    public int max_chunked_requests() {
        return max_chunked_requests;
    }

    public boolean enable_compaction() {
        return enable_compaction;
    }
}
